package com.itheima.health.service.impl;

import com.itheima.health.common.MessageConst;
import com.itheima.health.common.NumberConstant;
import com.itheima.health.dao.MemberDao;
import com.itheima.health.dao.OrderDao;
import com.itheima.health.dao.ReportDao;
import com.itheima.health.dao.SetMealDao;
import com.itheima.health.exception.BusinessRuntimeException;
import com.itheima.health.pojo.dto.SetmealOrderDTO;
import com.itheima.health.pojo.entity.HostSetmeal;
import com.itheima.health.pojo.entity.Order;
import com.itheima.health.pojo.vo.BusinessReportDataVO;
import com.itheima.health.pojo.vo.MemberReportVO;
import com.itheima.health.service.ReportService;
import lombok.extern.slf4j.Slf4j;
import org.apache.poi.xssf.usermodel.XSSFRow;
import org.apache.poi.xssf.usermodel.XSSFSheet;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;

import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;
import java.io.InputStream;
import java.text.DecimalFormat;
import java.time.*;
import java.time.format.DateTimeFormatter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Stream;

@Service
@Slf4j
public class ReportServiceImpl implements ReportService {
    public static final String REPORT_TEMPLATE_XLSX = "report_template.xlsx";
    public static final String REPORT_TEMPLATE_XLSX_SHEET_1 = "sheet1";
    public static final String TEMPLATE = "template/";
    public static final int II = 11;
    public static final int TWELVE = 12;

    @Autowired
    private SetMealDao setMealDao;
    @Autowired
    private MemberDao memberDao;

    @Autowired
    private OrderDao orderDao;

    @Autowired
    private ReportDao reportDao;

    /**
     * 统计分析-会员数量折线图
     *
     * @return
     */
    @Override
    public MemberReportVO getMemberReport() {
        // 1.获取日期列表
        ArrayList<String> months = new ArrayList<>();

        LocalDate now = LocalDate.now();

        LocalDate end = now.minusDays(1);
        LocalDate begin = end.minusYears(1);

        Stream<LocalDate> localDateStream = begin.datesUntil(end, Period.ofMonths(1));
        localDateStream.forEach(localDate -> {
            int year = localDate.getYear();
            int monthValue = localDate.getMonthValue();

            String month = String.valueOf(monthValue);
            if (month.length() == 1) {
                month = "0" + month;
            }

            String str = year + "." + month;
            months.add(str);
        });

        // 2。获取会员总数列表
        ArrayList<Integer> memberCount = new ArrayList<>();

        int dayOfMonth = now.getDayOfMonth();

        DateTimeFormatter dfm = DateTimeFormatter.ofPattern("yyyy.MM.dd");
        for (String month : months) {
            String date = month + "." + dayOfMonth;
            LocalDate parse = LocalDate.parse(date, dfm);
            Integer memberLT = memberDao.getByMemberLT(parse);
            memberCount.add(memberLT);
        }


        // 3.封装VO
        return MemberReportVO.builder()
                .months(months)
                .memberCount(memberCount)
                .build();
    }

    /**
     * 统计分析-运营数据统计页面展示
     *
     * @return
     */
    @Override
    public BusinessReportDataVO getBusinessReportData() {
        // 1.获取今日到诊人数
        LocalDate now = LocalDate.now();
        Integer todayVisitNumber = orderDao.getByFileNumberAndNow(Order.ORDERSTATUS_YES, now);

        // 2.获取今日新会员
        Integer todayNewMember = memberDao.getByNow(now);


        // 3.获取这周到诊人数
        LocalDate weekBefore = now.minusWeeks(1);
        Integer thisWeekVisitNumber = orderDao.getByFileNumber(Order.ORDERSTATUS_YES, now, weekBefore);
        // 4.获取热门套餐
        Integer totalOrder = orderDao.count();

        ArrayList<HostSetmeal> hotSetmeals = orderDao.getBySetmeal();
        DecimalFormat df = new DecimalFormat("0.00%");
        hotSetmeals.forEach(hostSetmeal -> {
            Integer setmealCount = hostSetmeal.getSetmealCount();
            double number = Double.parseDouble(String.valueOf(setmealCount)) / totalOrder;
            String formatNum = df.format(number);
            hostSetmeal.setProportion(formatNum);
        });

        // 5.获取本月新会员数
        LocalDate monthBefore = now.minusMonths(1);
        Integer thisMonthNewMember = memberDao.getByRegTime(now, monthBefore);

        // 6.获取本周新会员数
        Integer thisWeekNewMember = memberDao.getByRegTime(now, weekBefore);

        // 7.获取总会员数
        Integer totalMember = memberDao.getTotal();

        // 8.获取本月预约人数
        Integer thisMonthOrderNumber = orderDao.getByOrderDate(now, monthBefore);

        // 9.获取本月到诊人数
        Integer thisMonthVisitsNumber = orderDao.getByFileNumber(Order.ORDERSTATUS_YES, now, monthBefore);

        // 10.获取今日预约人数
        Integer todayOrderNumber = orderDao.getByNow(now);
        // 11.获取本周预约人数
        Integer thisWeekOrderNumber = orderDao.getByOrderDate(now, weekBefore);
        return BusinessReportDataVO.builder()
                .todayVisitNumber(todayVisitNumber)
                .reportDate(String.valueOf(LocalDate.now()))
                .todayNewMember(todayNewMember)
                .thisWeekVisitNumber(thisWeekVisitNumber)
                .hotSetmeal(hotSetmeals)
                .thisMonthNewMember(thisMonthNewMember)
                .thisWeekNewMember(thisWeekNewMember)
                .totalMember(totalMember)
                .thisMonthOrderNumber(thisMonthOrderNumber)
                .thisMonthVisitsNumber(thisMonthVisitsNumber)
                .todayOrderNumber(todayOrderNumber)
                .thisWeekOrderNumber(thisWeekOrderNumber)
                .build();
    }

    /**
     * 获取套餐预约占比统计
     *
     * @return
     */
    @Override
    public SetmealOrderDTO getSetmealReport() {
        SetmealOrderDTO setmealOrderDTO = new SetmealOrderDTO();
        //获取套餐名称
        List<String> setmealname = reportDao.getSetmealNames();
        String[] array = setmealname.toArray(new String[0]);
        //获取套餐预约数量
        List<Map<String, Object>> list = new ArrayList<>();
        for (String s : array) {
            //获取套餐预约数量
            //根据套餐名称获得套餐id
            Map<String, Object> map = new HashMap<>();
            Integer id = reportDao.getSetmealIdByName(s);
            Integer number = reportDao.getSetmealCountByName(id);
            map.put("name", s);
            map.put("value", number);
            list.add(map);
        }
        setmealOrderDTO.setSetmealCount(list);
        setmealOrderDTO.setSetmealNames(setmealname);
        return setmealOrderDTO;
    }

    /**
     * 统计分析-运营数据统计报表导出
     * @param response
     * @throws RuntimeException
     */
    @Override
    public void exportBusinessReport(HttpServletResponse response) throws RuntimeException {
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setHeader("Content-Disposition", "attachment; filename=business_report.xlsx");
        BusinessReportDataVO businessReportData = getBusinessReportData();
        try (InputStream inputStream = this.getClass().getClassLoader().getResourceAsStream(TEMPLATE + REPORT_TEMPLATE_XLSX);
             XSSFWorkbook workbook = new XSSFWorkbook(inputStream);
             ServletOutputStream outputStream = response.getOutputStream()) {

            XSSFSheet sheet = workbook.getSheet(REPORT_TEMPLATE_XLSX_SHEET_1);
            //第三行
            XSSFRow row3 = sheet.getRow(NumberConstant.TWO);
            row3.getCell(NumberConstant.FIVE).setCellValue(String.valueOf(LocalDate.now()));
            //第五行
            XSSFRow row5 = sheet.getRow(NumberConstant.FOUR);
            row5.getCell(NumberConstant.FIVE).setCellValue(businessReportData.getTodayNewMember());
            row5.getCell(NumberConstant.SEVEN).setCellValue(businessReportData.getTotalMember());
            //第六行
            XSSFRow row6 = sheet.getRow(NumberConstant.FIVE);
            row6.getCell(NumberConstant.FIVE).setCellValue(businessReportData.getThisMonthNewMember());
            row6.getCell(NumberConstant.SEVEN).setCellValue(businessReportData.getThisMonthOrderNumber());
            //8、9、10行（日、周、月）预约、到诊
            XSSFRow row8 = sheet.getRow(NumberConstant.SEVEN);
            row8.getCell(NumberConstant.FIVE).setCellValue(businessReportData.getTodayOrderNumber());
            row8.getCell(NumberConstant.SEVEN).setCellValue(businessReportData.getTodayVisitNumber());
            XSSFRow row9 = sheet.getRow(NumberConstant.EIGHT);
            row9.getCell(NumberConstant.FIVE).setCellValue(businessReportData.getThisWeekNewMember());
            row9.getCell(NumberConstant.SEVEN).setCellValue(businessReportData.getThisWeekVisitNumber());
            XSSFRow row10 = sheet.getRow(NumberConstant.NINE);
            row10.getCell(NumberConstant.FIVE).setCellValue(businessReportData.getThisMonthOrderNumber());
            row10.getCell(NumberConstant.SEVEN).setCellValue(businessReportData.getThisMonthVisitsNumber());
            ArrayList<HostSetmeal> hotSetmeal = businessReportData.getHotSetmeal();
            int startCell = NumberConstant.FOUR;
            for (int i = TWELVE; i <TWELVE+hotSetmeal.size(); i++) {
                XSSFRow row = sheet.getRow(i);
                HostSetmeal hostSetmeal = hotSetmeal.get(i-TWELVE);
                row.getCell(startCell).setCellValue(hostSetmeal.getName());
                row.getCell(startCell+NumberConstant.ONE).setCellValue(hostSetmeal.getProportion());
                row.getCell(startCell+NumberConstant.TWO).setCellValue(hostSetmeal.getSetmealCount());
                String remark=setMealDao.selectRemarkByName(hostSetmeal.getName());
                row.getCell(startCell+NumberConstant.THREE).setCellValue(remark);
            }
            workbook.write(outputStream);
        } catch (IOException e) {
            e.printStackTrace();
            throw new BusinessRuntimeException(MessageConst.ACTION_FAIL);
        }
    }

}
